home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / net_src.arc / lapb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-08  |  14.9 KB  |  630 lines

  1. /* Link Access Procedures Balanced (LAPB) - with changes for rational
  2.  * behavior over packet radio
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "ax25.h"
  8. #include "lapb.h"
  9. #include "iface.h"
  10.  
  11. /* Process incoming frames */
  12. int
  13. lapb_input(axp,cmdrsp,bp)
  14. struct ax25_cb *axp;        /* Link control structure */
  15. char cmdrsp;            /* Command/response flag */
  16. struct mbuf *bp;        /* Rest of frame, starting with ctl */
  17. {
  18.     int16 ftype();
  19.     void lapbstate();
  20.     char control;
  21.     char class;        /* General class (I/S/U) of frame */
  22.     int16 type;        /* Specific type (I/RR/RNR/etc) of frame */
  23.     char pf;        /* extracted poll/final bit */
  24.     char poll = 0;
  25.     char final = 0;
  26.     int nr;            /* ACK number of incoming frame */
  27.     int ns;            /* Seq number of incoming frame */
  28.     char tmp;
  29.  
  30.     if(bp == NULLBUF || axp == NULLAX25){
  31.         free_p(bp);
  32.         return -1;
  33.     }
  34.  
  35.     /* Extract the various parts of the control field for easy use */
  36.     control = pullchar(&bp);
  37.     type = ftype(control);
  38.     class = type & 0x3;
  39.     pf = control & PF;
  40.     /* Check for polls and finals */
  41.     if(pf){
  42.         switch(cmdrsp){
  43.         case COMMAND:
  44.             poll = YES;
  45.             break;
  46.         case RESPONSE:
  47.             final = YES;
  48.             break;
  49.         }
  50.     }
  51.     /* Extract sequence numbers, if present */
  52.     switch(class){
  53.     case I:
  54.     case I+2:
  55.         ns = (control >> 1) & MMASK;
  56.     case S:    /* Note fall-thru */
  57.         nr = (control >> 5) & MMASK;
  58.         break;
  59.     }
  60.     /* This section follows the SDL diagrams by K3NA fairly closely */
  61.     switch(axp->state){
  62.     case DISCONNECTED:
  63.         switch(type){
  64.         case SABM:    /* Initialize or reset link */
  65.             sendctl(axp,RESPONSE,UA|pf);    /* Always accept */
  66.             clr_ex(axp);
  67.             axp->unack = axp->vr = axp->vs = 0;
  68.             lapbstate(axp,CONNECTED);/* Resets state counters */
  69.             start_timer(&axp->t3);
  70.             break;
  71.         case DM:    /* Ignore to avoid infinite loops */
  72.             break;
  73.         default:    /* All others get DM */
  74.             sendctl(axp,RESPONSE,DM|pf);
  75.             break;
  76.         }
  77.         break;
  78.     case SETUP:
  79.         switch(type){
  80.         case SABM:    /* Simultaneous open */
  81.             sendctl(axp,RESPONSE,UA|pf);
  82.             break;
  83.         case DISC:
  84.             sendctl(axp,RESPONSE,DM|pf);
  85.             break;
  86.         case UA:    /* Connection accepted */
  87.             /* Note: xmit queue not cleared */
  88.             stop_timer(&axp->t1);
  89.             start_timer(&axp->t3);
  90.             axp->unack = axp->vr = axp->vs = 0;
  91.             lapbstate(axp,CONNECTED);
  92.             break;            
  93.         case DM:    /* Connection refused */
  94.             free_q(&axp->txq);
  95.             stop_timer(&axp->t1);
  96.             lapbstate(axp,DISCONNECTED);
  97.             break;
  98.         default:    /* All other frames ignored */
  99.             break;
  100.         }
  101.         break;
  102.     case DISCPENDING:
  103.         switch(type){
  104.         case SABM:
  105.             sendctl(axp,RESPONSE,DM|pf);
  106.             break;
  107.         case DISC:
  108.             sendctl(axp,RESPONSE,UA|pf);
  109.             break;
  110.         case UA:
  111.         case DM:
  112.             stop_timer(&axp->t1);
  113.             lapbstate(axp,DISCONNECTED);
  114.             break;
  115.         default:    /* Respond with DM only to command polls */
  116.             if(poll)
  117.                 sendctl(axp,RESPONSE,DM|pf);
  118.             break;
  119.         }
  120.         break;
  121.     case CONNECTED:
  122.         switch(type){
  123.         case SABM:
  124.             sendctl(axp,RESPONSE,UA|pf);
  125.             clr_ex(axp);
  126.             free_q(&axp->txq);
  127.             stop_timer(&axp->t1);
  128.             start_timer(&axp->t3);
  129.             axp->unack = axp->vr = axp->vs = 0;
  130.             lapbstate(axp,CONNECTED); /* Purge queues */
  131.             break;
  132.         case DISC:
  133.             free_q(&axp->txq);
  134.             sendctl(axp,RESPONSE,UA|pf);
  135.             stop_timer(&axp->t1);
  136.             stop_timer(&axp->t3);
  137.             lapbstate(axp,DISCONNECTED);
  138.             break;
  139. /* This code is cribbed from the NOS version, in order to make a */
  140. /* temporary fix to a pathological looping behavior during connect (dmf) */
  141.         case DM:
  142.             lapbstate(axp,DISCONNECTED);
  143.             break;
  144.         case UA:
  145.             est_link(axp);
  146.             lapbstate(axp,SETUP);    /* Re-establish */    
  147.             break;
  148. /* End of cribbed code (dmf) */            
  149.         case FRMR:
  150.             est_link(axp);
  151.             lapbstate(axp,SETUP);    /* Re-establish link */
  152.             break;
  153.         case RR:
  154.         case RNR:
  155.             axp->remotebusy = (control == RNR) ? YES : NO;
  156.             if(poll)
  157.                 enq_resp(axp);
  158.             ackours(axp,nr);
  159.             break;
  160.         case REJ:
  161.             axp->remotebusy = NO;
  162.             if(poll)
  163.                 enq_resp(axp);
  164.             ackours(axp,nr);
  165.             stop_timer(&axp->t1);
  166.             start_timer(&axp->t3);
  167.             /* This may or may not actually invoke transmission,
  168.              * depending on whether this REJ was caused by
  169.              * our losing his prior ACK.
  170.              */
  171.             inv_rex(axp);
  172.             break;    
  173.         case I:
  174.             ackours(axp,nr); /** == -1) */
  175.             if(len_mbuf(axp->rxq) >= axp->window){
  176.                 /* Too bad he didn't listen to us; he'll
  177.                  * have to resend the frame later. This
  178.                  * drastic action is necessary to avoid
  179.                  * deadlock.
  180.                  */
  181.                 if(poll)
  182.                     sendctl(axp,RESPONSE,RNR|pf);
  183.                 free_p(bp);
  184.                 bp = NULLBUF;
  185.                 break;
  186.             }
  187.             /* Reject or ignore I-frames with receive sequence number errors */
  188.             if(ns != axp->vr){
  189.                 if(axp->proto == V1 || !axp->rejsent){
  190.                     axp->rejsent = YES;
  191.                     sendctl(axp,RESPONSE,REJ | pf);
  192.                 }
  193.                 axp->response = 0;
  194.                 stop_timer(&axp->t2);
  195.                 break;
  196.             }
  197.             axp->rejsent = NO;
  198.             axp->vr = (axp->vr+1) & MMASK;
  199.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  200.             if(poll){
  201.                 sendctl(axp,RESPONSE,tmp|PF);
  202.             } else {
  203.                 axp->response = tmp;
  204.                 start_timer(&axp->t2);
  205.             }
  206.             procdata(axp,bp);
  207.             bp = NULLBUF;
  208.             break;
  209.         default:    /* All others ignored */
  210.             break;
  211.         }
  212.         break;
  213.     case RECOVERY:
  214.         switch(type){
  215.         case SABM:
  216.             sendctl(axp,RESPONSE,UA|pf);
  217.             clr_ex(axp);
  218.             stop_timer(&axp->t1);
  219.             start_timer(&axp->t3);
  220.             axp->unack = axp->vr = axp->vs = 0;
  221.             lapbstate(axp,CONNECTED); /* Purge queues */
  222.             break;
  223.         case DISC:
  224.             free_q(&axp->txq);
  225.             sendctl(axp,RESPONSE,UA|pf);
  226.             stop_timer(&axp->t1);
  227.             stop_timer(&axp->t3);
  228.             axp->response = UA;
  229.             lapbstate(axp,DISCONNECTED);
  230.             break;
  231. /* This code is cribbed from the NOS version, in order to make a */
  232. /* temporary fix to a pathological looping behavior during connect (dmf) */
  233.         case DM:
  234.             lapbstate(axp,DISCONNECTED);
  235.             break;
  236.         case UA:
  237.             est_link(axp);
  238.             lapbstate(axp,SETUP);    /* Re-establish */    
  239.             break;
  240. /* End of cribbed code (dmf) */            
  241.         case FRMR:
  242.             est_link(axp);
  243.             lapbstate(axp,SETUP);    /* Re-establish link */
  244.             break;
  245.         case RR:
  246.         case RNR:
  247.             axp->remotebusy = (control == RNR) ? YES : NO;
  248.             if(axp->proto == V1 || final){
  249.                 stop_timer(&axp->t1);
  250.                 ackours(axp,nr);
  251.                 if(axp->unack != 0){
  252.                     inv_rex(axp);
  253.                 } else {
  254.                     start_timer(&axp->t3);
  255.                     lapbstate(axp,CONNECTED);
  256.                 }
  257.             } else {
  258.                 if(poll)
  259.                     enq_resp(axp);
  260.                 ackours(axp,nr);
  261.                 /* Keep timer running even if all frames
  262.                  * were acked, since we must see a Final
  263.                  */
  264.                 if(!run_timer(&axp->t1))
  265.                     start_timer(&axp->t1);
  266.             }
  267.             break;
  268.         case REJ:
  269.             axp->remotebusy = NO;
  270.             /* Don't insist on a Final response from the old proto */
  271.             if(axp->proto == V1 || final){
  272.                 stop_timer(&axp->t1);
  273.                 ackours(axp,nr);
  274.                 if(axp->unack != 0){
  275.                     inv_rex(axp);
  276.                 } else {
  277.                     start_timer(&axp->t3);
  278.                     lapbstate(axp,CONNECTED);
  279.                 }
  280.             } else {
  281.                 if(poll)
  282.                     enq_resp(axp);
  283.                 ackours(axp,nr);
  284.                 if(axp->unack != 0){
  285.                     /* This is certain to trigger output */
  286.                     inv_rex(axp);
  287.                 }
  288.                 /* A REJ that acks everything but doesn't
  289.                  * have the F bit set can cause a deadlock.
  290.                  * So make sure the timer is running.
  291.                  */
  292.                 if(!run_timer(&axp->t1))
  293.                     start_timer(&axp->t1);
  294.             }
  295.             break;
  296.         case I:
  297.             ackours(axp,nr); /** == -1) */
  298.             /* Make sure timer is running, since an I frame
  299.              * cannot satisfy a poll
  300.              */
  301.             if(!run_timer(&axp->t1))
  302.                 start_timer(&axp->t1);
  303.             if(len_mbuf(axp->rxq) >= axp->window){
  304.                 /* Too bad he didn't listen to us; he'll
  305.                  * have to resend the frame later. This
  306.                  * drastic action is necessary to avoid
  307.                  * memory deadlock.
  308.                  */
  309.                 sendctl(axp,RESPONSE,RNR | pf);
  310.                 free_p(bp);
  311.                 bp = NULLBUF;
  312.                 break;
  313.             }
  314.             /* Reject or ignore I-frames with receive sequence number errors */
  315.             if(ns != axp->vr){
  316.                 if(axp->proto == V1 || !axp->rejsent){
  317.                     axp->rejsent = YES;
  318.                     sendctl(axp,RESPONSE,REJ | pf);
  319.                 }
  320.                 axp->response = 0;
  321.                 stop_timer(&axp->t2);
  322.                 break;
  323.             }
  324.             axp->rejsent = NO;
  325.             axp->vr = (axp->vr+1) & MMASK;
  326.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  327.             if(poll){
  328.                 sendctl(axp,RESPONSE,tmp|PF);
  329.             } else {
  330.                 axp->response = tmp;
  331.                 start_timer(&axp->t2);
  332.             }
  333.             procdata(axp,bp);
  334.             bp = NULLBUF;
  335.             break;
  336.         default:
  337.             break;        /* Ignored */
  338.         }
  339.         break;
  340.     case FRAMEREJECT:
  341.         switch(type){
  342.         case SABM:
  343.             sendctl(axp,RESPONSE,UA|pf);
  344.             clr_ex(axp);
  345.             axp->unack = axp->vr = axp->vs = 0;
  346.             stop_timer(&axp->t1);
  347.             start_timer(&axp->t3);
  348.             lapbstate(axp,CONNECTED);
  349.             break;
  350.         case DISC:
  351.             free_q(&axp->txq);
  352.             sendctl(axp,RESPONSE,UA|pf);
  353.             stop_timer(&axp->t1);
  354.             lapbstate(axp,DISCONNECTED);
  355.             break;
  356.         case DM:
  357.             stop_timer(&axp->t1);
  358.             lapbstate(axp,DISCONNECTED);
  359.             break;
  360.         default:
  361.             frmr(axp,0,0);
  362.             break;
  363.         }
  364.         break;
  365.     }
  366.     free_p(bp);    /* In case anything's left */
  367.  
  368.     /* See if we can send some data, perhaps piggybacking an ack.
  369.      * If successful, lapb_output will clear axp->response.
  370.      */
  371.     lapb_output(axp);
  372.  
  373.     /* Empty the trash */
  374.     if(axp->state == DISCONNECTED)
  375.         del_ax25(axp);
  376.     return 0;
  377. }
  378. /* Handle incoming acknowledgements for frames we've sent.
  379.  * Free frames being acknowledged.
  380.  * Return -1 to cause a frame reject if number is bad, 0 otherwise
  381.  */
  382. static int
  383. ackours(axp,n)
  384. struct ax25_cb *axp;
  385. char n;
  386. {    
  387.     struct mbuf *bp;
  388.     int acked = 0;    /* Count of frames acked by this ACK */
  389.     int oldest;    /* Seq number of oldest unacked I-frame */
  390.  
  391.     /* Free up acknowledged frames by purging frames from the I-frame
  392.      * transmit queue. Start at the remote end's last reported V(r)
  393.      * and keep going until we reach the new sequence number.
  394.      * If we try to free a null pointer,
  395.      * then we have a frame reject condition.
  396.      */
  397.     oldest = (axp->vs - axp->unack) & MMASK;
  398.     while(axp->unack != 0 && oldest != n){
  399.         if((bp = dequeue(&axp->txq)) == NULLBUF){
  400.             /* Acking unsent frame */
  401.             return -1;
  402.         }
  403.         free_p(bp);
  404.         axp->unack--;
  405.         acked++;
  406.         axp->retries = 0;
  407.         oldest = (oldest + 1) & MMASK;
  408.     }
  409.     if(axp->unack == 0){
  410.         /* All frames acked, stop timeout */
  411.         stop_timer(&axp->t1);
  412.         start_timer(&axp->t3);
  413.     } else if(acked != 0) { 
  414.         /* Partial ACK; restart timer */
  415.         start_timer(&axp->t1);
  416.     }
  417.     /* If user has set a transmit upcall, indicate how many frames
  418.      * may be queued
  419.      */
  420.     if(acked != 0 && axp->t_upcall != NULLVFP)
  421.         (*axp->t_upcall)(axp,axp->paclen * (axp->maxframe - axp->unack));
  422.  
  423.     return 0;
  424. }
  425.  
  426. /* Establish data link */
  427. est_link(axp)
  428. struct ax25_cb *axp;
  429. {
  430.     clr_ex(axp);
  431.     axp->retries = 0;
  432.     sendctl(axp,COMMAND,SABM|PF);
  433.     stop_timer(&axp->t3);
  434.     start_timer(&axp->t1);
  435. }
  436. /* Clear exception conditions */
  437. clr_ex(axp)
  438. struct ax25_cb *axp;
  439. {
  440.     axp->remotebusy = NO;
  441.     axp->rejsent = NO;
  442.     axp->response = 0;
  443.     stop_timer(&axp->t3);
  444. }
  445. /* Enquiry response */
  446. enq_resp(axp)
  447. struct ax25_cb *axp;
  448. {
  449.     char ctl;
  450.  
  451.     ctl = len_mbuf(axp->rxq) >= axp->window ? RNR|PF : RR|PF;    
  452.     sendctl(axp,RESPONSE,ctl);
  453.     axp->response = 0;
  454.     stop_timer(&axp->t3);
  455. }
  456. /* Invoke retransmission */
  457. inv_rex(axp)
  458. struct ax25_cb *axp;
  459. {
  460.     axp->vs -= axp->unack;
  461.     axp->vs &= MMASK;
  462.     axp->unack = 0;
  463. }
  464. /* Generate Frame Reject (FRMR) response
  465.  * If reason != 0, this is the initial error frame
  466.  * If reason == 0, resend the last error frame
  467.  */
  468. int
  469. frmr(axp,control,reason)
  470. register struct ax25_cb *axp;
  471. char control;
  472. char reason;
  473. {
  474.     struct mbuf *frmrinfo;
  475.     register char *cp;
  476.     void lapbstate();
  477.  
  478.     if(reason != 0){
  479.         cp = axp->frmrinfo;
  480.         *cp++ = control;
  481.         *cp++ =  axp->vr << 5 || axp->vs << 1;
  482.         *cp = reason;
  483.     }
  484.     if((frmrinfo = alloc_mbuf(3)) == NULLBUF)
  485.         return -1;    /* No memory */
  486.     frmrinfo->cnt = 3;
  487.     memcpy(frmrinfo->data,axp->frmrinfo,3);
  488.     return sendframe(axp,RESPONSE,FRMR|(control&PF),frmrinfo);
  489. }
  490.  
  491. /* Send S or U frame to currently connected station */
  492. int
  493. sendctl(axp,cmdrsp,cmd)
  494. struct ax25_cb *axp;
  495. char cmdrsp,cmd;
  496. {
  497.     int16 ftype();
  498.  
  499.     if((ftype(cmd) & 0x3) == S)    /* Insert V(R) if S frame */
  500.         cmd |= (axp->vr << 5);
  501.     return sendframe(axp,cmdrsp,cmd,NULLBUF);
  502. }
  503. /* Start data transmission on link, if possible
  504.  * Return number of frames sent
  505.  */
  506. int
  507. lapb_output(axp)
  508. register struct ax25_cb *axp;
  509. {
  510.     register struct mbuf *bp;
  511.     struct mbuf *tbp;
  512.     char control;
  513.     int sent = 0;
  514.     int i;
  515.  
  516.     if(axp == NULLAX25
  517.      || (axp->state != RECOVERY && axp->state != CONNECTED)
  518.      || axp->remotebusy)
  519.         return 0;
  520.  
  521.     /* Dig into the send queue for the first unsent frame */
  522.     bp = axp->txq;
  523.     for(i = 0; i < axp->unack; i++){
  524.         if(bp == NULLBUF)
  525.             break;    /* Nothing to do */
  526.         bp = bp->anext;
  527.     }
  528.     /* Start at first unsent I-frame, stop when either the
  529.      * number of unacknowledged frames reaches the maxframe limit,
  530.      * or when there are no more frames to send
  531.      */
  532.     while(bp != NULLBUF && axp->unack < axp->maxframe){
  533.         control = I | (axp->vs++ << 1) | (axp->vr << 5);
  534.         axp->vs &= MMASK;
  535.         dup_p(&tbp,bp,0,len_mbuf(bp));
  536.         if(tbp == NULLBUF)
  537.             return sent;    /* Probably out of memory */
  538.         sendframe(axp,COMMAND,control,tbp);
  539.         axp->unack++;
  540.         /* We're implicitly acking any data he's sent, so stop any
  541.          * delayed ack
  542.          */
  543.         axp->response = 0;
  544.         stop_timer(&axp->t2);
  545.         if(!run_timer(&axp->t1)){
  546.             stop_timer(&axp->t3);
  547.             start_timer(&axp->t1);
  548.         }
  549.         sent++;
  550.         bp = bp->anext;
  551.     }
  552.     return sent;
  553. }
  554. /* Set new link state.
  555.  * If the new state is disconnected, also free the link control block.
  556.  */
  557. void
  558. lapbstate(axp,s)
  559. struct ax25_cb *axp;
  560. int s;
  561. {
  562.     int oldstate;
  563.  
  564.     oldstate = axp->state;
  565.     axp->state = s;
  566.     if(s == DISCONNECTED){
  567.         stop_timer(&axp->t1);
  568.         stop_timer(&axp->t2);
  569.         stop_timer(&axp->t3);
  570.         free_q(&axp->txq);
  571.     }
  572.     /* Don't bother the client unless the state is really changing */
  573.     if(oldstate != s && axp->s_upcall != NULLVFP)
  574.         (*axp->s_upcall)(axp,oldstate,s);
  575. }
  576. /* Process a valid incoming I frame */
  577. static
  578. procdata(axp,bp)
  579. struct ax25_cb *axp;
  580. struct mbuf *bp;
  581. {
  582.     char pid;
  583.     int ip_route();
  584.  
  585.     /* Extract level 3 PID */
  586.     if(pullup(&bp,&pid,1) != 1)
  587.         return;    /* No PID */
  588.  
  589.     switch(pid & (PID_FIRST|PID_LAST)){
  590.     case PID_FIRST:
  591.         /* "Shouldn't happen", but flush any accumulated frags */
  592.         free_p(axp->rxasm);
  593.         axp->rxasm = NULLBUF;
  594.     case 0:    /* Note fall-thru */
  595.         /* Beginning or middle of message, just accumulate */
  596.         append(&axp->rxasm,bp);
  597.         return;
  598.     case PID_LAST:
  599.         /* Last frame of multi-frame message; extract it */
  600.         append(&axp->rxasm,bp);
  601.         bp = axp->rxasm;
  602.         axp->rxasm = NULLBUF;
  603.         break;
  604.     case PID_FIRST|PID_LAST:
  605.         /* Do nothing with reassembly queue, allowing single-frame
  606.          * messages to be interspersed with fragments of multi-frame
  607.          * messages
  608.          */
  609.         break;
  610.     }
  611.     /* Last frame in sequence; kick entire message upstairs */
  612.     switch(pid & PID_PID){
  613.     case PID_IP:        /* DoD Internet Protocol */
  614.         ip_route(bp,0);
  615.         break;
  616.     case PID_NO_L3:        /* Enqueue for application */
  617.         append(&axp->rxq,bp);
  618.         if(axp->r_upcall != NULLVFP)
  619.             (*axp->r_upcall)(axp,len_mbuf(axp->rxq));
  620.         break;    
  621.     case PID_NETROM:
  622.         nr_route(bp,axp);
  623.         break;
  624.     default:        /* Note: ARP is invalid here */    
  625.         free_p(bp);
  626.         break;            
  627.     }
  628. }
  629.  
  630.